/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>

#include "yaffut.h"
#include "myassert.h"
#include "TestConnection.h"

#include "Connection.h"
#include "LoginSession.h"

#include "TestDatabase.h"
#include "MudPlayer.h"
#include "AliasList.h"

using namespace std;
using namespace Chronos;

struct LoginSessionTest {
	LoginSessionTest()
        : database()
		, connectionClosed(false)
		, connection(new TestConnection(&connectionClosed))
		, login(connection, database)
        , pulse(0)  
	{
		ASSERT_FALSE(connectionClosed);
		connection->CONNECTION_CHECKWRITTEN("Welcome to Example Mud\nname: ");
	}

	void testInputResult(unsigned int pulse_, const std::string& input, const std::string& output, int expected) {
        while (pulse_ != 0 && pulse < pulse_ -1) {
            connection->setOutput("");
            login.handlePulse();
            ++pulse;
        }
		connection->setOutput(input);
        int result = login.handlePulse();
		connection->CONNECTION_CHECKWRITTEN(output);
		ASSERT_EQUAL(expected, result);
	}

    TestDatabase database;
	bool connectionClosed;
	TestConnection* connection;
	LoginSession login;
    unsigned int pulse;
    static const unsigned int TIMEOUT = 150;
};


TEST(LoginSessionTest, testShouldLogin) {
	testInputResult(1, "player", "password: ", LoginSession::INPROGRESS);
	testInputResult(2, "player123", "", LoginSession::SUCCESS);
}


TEST(LoginSessionTest, testManyTriesLogin) {
	testInputResult(1, "ENTER", "name: ", LoginSession::INPROGRESS);
	testInputResult(150, "ENTER", "name: ", LoginSession::INPROGRESS);
	testInputResult(300, "player", "password: ", LoginSession::INPROGRESS);
	testInputResult(450, "ENTER", "password: ", LoginSession::INPROGRESS);
	testInputResult(600, "wrong", "password incorrect!\npassword: ", LoginSession::INPROGRESS);
	testInputResult(750, "player123", "", LoginSession::SUCCESS);
}


TEST(LoginSessionTest, testCloseOnWrongRead) {
	testInputResult(1, "", "", LoginSession::INPROGRESS);
	testInputResult(2, "ERROR", "", LoginSession::FAIL);
}


TEST(LoginSessionTest, testGivingEmptyLinesAtName) {
	testInputResult(1, "ENTER", "name: ", LoginSession::INPROGRESS);
	testInputResult(2, "ENTER", "name: ", LoginSession::INPROGRESS);
	testInputResult(3, "ENTER", "Bye!\n", LoginSession::FAIL);
}


TEST(LoginSessionTest, testGivingEmptyLinesAtPassword) {
	testInputResult(1, "player", "password: ", LoginSession::INPROGRESS);
	testInputResult(2, "ENTER", "password: ", LoginSession::INPROGRESS);
	testInputResult(3, "ENTER", "password: ", LoginSession::INPROGRESS);
	testInputResult(4, "ENTER", "Bye!\n", LoginSession::FAIL);
}


TEST(LoginSessionTest, testTimeOutAtName) {
	testInputResult(TIMEOUT, "", "", LoginSession::INPROGRESS);
	testInputResult(TIMEOUT+1, "", "(timeout)\n", LoginSession::FAIL);
}


TEST(LoginSessionTest, testTimeOutAtPassword) {
	testInputResult(0, "player", "password: ", LoginSession::INPROGRESS);
	testInputResult(TIMEOUT, "", "", LoginSession::INPROGRESS);
	testInputResult(TIMEOUT+1, "", "(timeout)\n", LoginSession::FAIL);
}


TEST(LoginSessionTest, testTimeOutWithEnter) {
	testInputResult(0, "player", "password: ", LoginSession::INPROGRESS);
	testInputResult(TIMEOUT, "", "", LoginSession::INPROGRESS);
	testInputResult(TIMEOUT+1, "ENTER", "(timeout)\n", LoginSession::FAIL);
}


TEST(LoginSessionTest, testCloseAfterWrongPasswords) {
	testInputResult(1, "player", "password: ", LoginSession::INPROGRESS);
	testInputResult(2, "wrong1", "password incorrect!\npassword: ", LoginSession::INPROGRESS);
	testInputResult(3, "wrong2", "password incorrect!\npassword: ", LoginSession::INPROGRESS);
	testInputResult(4, "wrong3", "password incorrect!\nBye!\n", LoginSession::FAIL);
}


TEST(LoginSessionTest, testLoginUnknownUser) {
	testInputResult(1, "newplayer", "Unknown player. Type 'new' to create a new player.\nname: ", LoginSession::INPROGRESS);
	testInputResult(2, "newplayer", "Unknown player. Type 'new' to create a new player.\nname: ", LoginSession::INPROGRESS);
	testInputResult(3, "newplayer", "Bye!\n", LoginSession::FAIL);
}


TEST(LoginSessionTest, testLoginNewPlayer) {
	testInputResult(1, "newplayer", "Unknown player. Type 'new' to create a new player.\nname: ", LoginSession::INPROGRESS);
	testInputResult(2, "new", "", LoginSession::NEW_PLAYER);
}


TEST(LoginSessionTest, testQuit) {
	testInputResult(1, "quit", "Goodbye!\n", LoginSession::FAIL);
}

